package net.hpxn.gsmc.action;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import net.hpxn.gsmc.config.ConfigFactory;
import net.hpxn.gsmc.config.usercountlogger.UserCountLoggerConfig;

import org.apache.log4j.Logger;

import org.jrobin.core.*;
import org.jrobin.graph.*;

/*
 * This action will generate RRDTool graphs that represent server usage 
 * based on concurrent user counts. This class depends upon the 
 * StatusUpdateAction. If the StatusUpdateAction is not enabled for the 
 * specific server then the player count will never be updated.
 */
public class UserCountLogger extends BaseAction {
	protected Logger log;
	private String rrdFilePath;
	private String rrdFileName;

	private static final String IMAGE_TYPE = "png";

	private static final String IMAGE_DAILY = "-players-daily.png";
	private static final String IMAGE_WEEKLY = "-players-weekly.png";
	private static final String IMAGE_MONTHLY = "-players-monthly.png";
	private static final String IMAGE_YEARLY = "-players-yearly.png";

	private int POLL_RESOLUTION = 30;

	private RrdDbPool rrdPool;

	private static UserCountLoggerConfig loggerConfig;

	private String serverName;

	public UserCountLogger() {
		log = Logger.getLogger( this.getClass().getCanonicalName() );
		if ( loggerConfig == null ) {
			try {
				loggerConfig = ConfigFactory.getUserCountLoggerConfig();
			} catch ( Exception e ) {
				log.error( "Error loading UserCountLogger configuration: "
						+ e.getMessage() );
				e.printStackTrace();
			}
		}

		try {
			rrdPool = RrdDbPool.getInstance();
		} catch ( RrdException e ) {
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		serverName = getEvent().getServer().getName().toLowerCase();
		rrdFilePath = loggerConfig.getSaveFilePath();
		rrdFileName = serverName + ".rrd";

		try {
			createRrdFileIfNecessary();
		} catch ( RrdException e ) {
			e.printStackTrace();
		} catch ( IOException e ) {
			e.printStackTrace();
		}

		while ( isRunning() ) {
			try {
				RrdDb rrdDb = rrdPool.requestRrdDb( rrdFilePath + rrdFileName );
				// create sample with the current timestamp
				Sample sample = rrdDb.createSample();
				// set value for load datasource
				sample.setValue( "count", getEvent().getServer()
						.getPlayerCount() );
				// update database
				sample.update();
				// release RRD database reference
				rrdPool.release( rrdDb );
			} catch ( IOException e ) {
				e.printStackTrace();
			} catch ( RrdException e ) {
				e.printStackTrace();
			}
			
			if ( loggerConfig.getDrawGraphs().equalsIgnoreCase( "true" ) ) {
				try {
					drawGraphs();
				} catch ( RrdException e ) {
					e.printStackTrace();
				} catch ( IOException e ) {
					e.printStackTrace();
				}
			}
			
			try {
				Thread.sleep( POLL_RESOLUTION * 1000 );
			} catch ( InterruptedException e ) {
				// k.
			}
		}
	}

	private void createRrdFileIfNecessary() throws RrdException, IOException {
		File rrdFile = new File( rrdFilePath + rrdFileName );
		if ( !rrdFile.exists() ) {
			// create RRD file since it does not exist
			RrdDef rrdDef = new RrdDef( rrdFilePath + rrdFileName,
					POLL_RESOLUTION );
			// single gauge datasource, named 'count'
			rrdDef.addDatasource( "count", "GAUGE", 2 * POLL_RESOLUTION, 0,
					Double.NaN );
			// an archive
			rrdDef.addArchive( "MAX", 0.5, 1, 262080 );
			// create RRD file in the pool
			RrdDb rrdDb = rrdPool.requestRrdDb( rrdDef );
			rrdPool.release( rrdDb );
		}
	}

	private void drawGraphs() throws RrdException, IOException {
		// create common part of graph definition
		// time span will be set later
		final RrdGraphDef graphDef = new RrdGraphDef();
		graphDef.datasource( "count", rrdFilePath + rrdFileName, "count", "MAX" );
		graphDef.area( "count", Color.BLUE, "# of Players" );
		graphDef.setAntiAliasing( true );
		graphDef.setLazy( true );
		graphDef.setShowSignature( false );
		graphDef.setVerticalLabel( "# of Players" );
		graphDef.setNoLegend( true );
		graphDef.comment( "GSMC - Game Server Monitoring and Communications" );

		// ending timestamp is the current timestamp
		// starting timestamp will be adjusted for each graph
		long startTime, endTime = Util.getTime();
		RrdGraph rrdGraph;

		// daily graph
		startTime = endTime - 86400;
		graphDef.setTimeSpan( startTime, endTime );
		graphDef.setTitle( serverName + " - Players Connected - 1 day" );
		rrdGraph = new RrdGraph( graphDef );

		// write daily graph
		BufferedImage bImage = new BufferedImage( rrdGraph.getRrdGraphInfo()
				.getWidth(), rrdGraph.getRrdGraphInfo().getHeight(),
				BufferedImage.TYPE_INT_RGB );
		Graphics2D g = bImage.createGraphics();
		rrdGraph.render( g );
		ImageIO.write( bImage, IMAGE_TYPE, new File( rrdFilePath + serverName
				+ IMAGE_DAILY ) );
		g.dispose();

		// weekly graph
		startTime = endTime - 86400 * 7;
		graphDef.setTimeSpan( startTime, endTime );
		graphDef.setTitle( serverName + " - Players Connected - 1 week" );
		rrdGraph = new RrdGraph( graphDef );

		// write weekly graph
		bImage = new BufferedImage( rrdGraph.getRrdGraphInfo().getWidth(),
				rrdGraph.getRrdGraphInfo().getHeight(),
				BufferedImage.TYPE_INT_RGB );
		g = bImage.createGraphics();
		rrdGraph.render( g );
		ImageIO.write( bImage, IMAGE_TYPE, new File( rrdFilePath + serverName
				+ IMAGE_WEEKLY ) );
		g.dispose();

		// monthly graph
		startTime = endTime - 86400 * 31;
		graphDef.setTimeSpan( startTime, endTime );
		graphDef.setTitle( serverName + " - Players Connected - 1 month" );
		rrdGraph = new RrdGraph( graphDef );

		// write monthly graph
		bImage = new BufferedImage( rrdGraph.getRrdGraphInfo().getWidth(),
				rrdGraph.getRrdGraphInfo().getHeight(),
				BufferedImage.TYPE_INT_RGB );
		g = bImage.createGraphics();
		rrdGraph.render( g );
		ImageIO.write( bImage, IMAGE_TYPE, new File( rrdFilePath + serverName
				+ IMAGE_MONTHLY ) );
		g.dispose();

		// yearly graph
		startTime = endTime - 86400 * 366;
		graphDef.setTimeSpan( startTime, endTime );
		graphDef.setTitle( serverName + " - Players Connected - 1 year" );
		rrdGraph = new RrdGraph( graphDef );

		// write yearly graph
		bImage = new BufferedImage( rrdGraph.getRrdGraphInfo().getWidth(),
				rrdGraph.getRrdGraphInfo().getHeight(),
				BufferedImage.TYPE_INT_RGB );
		g = bImage.createGraphics();
		rrdGraph.render( g );
		ImageIO.write( bImage, IMAGE_TYPE, new File( rrdFilePath + serverName
				+ IMAGE_YEARLY ) );
		g.dispose();
	}
}
